import type { MappingConfig, MappingRule, MapperPlugin, NormalizedRule, MappingContext, Path, PluginHooks } from './types';

// ======================== 🚀 核心实现 ========================

/**
 * 🌟 对象映射器核心类
 * @example - 基础用法
 * const mapper = new ObjectMapper();
 * const result = mapper.map(sourceData, [
 *   { target: 'fullName', source: 'name' },
 *   'age:userAge' // 简写语法
 * ]);
 */
export class ObjectMapper {
  private config: MappingConfig;
  private pathCache = new Map<string, string[]>();
  private plugins = new Set<MapperPlugin>();

  constructor(config: Partial<MappingConfig> = {}) {
    this.config = Object.freeze({
      strict: false,
      nullPolicy: 'set-null',
      autoType: false,
      cachePaths: false,
      ...config
    });
  }

  /**
   * 🔌 注册插件
   * @param plugin - 实现PluginHooks的插件对象
   * @example - 日志插件
   * mapper.use({
   *   beforeMap: (ctx) => console.log('开始映射', ctx.source)
   * });
   */
  use(plugin: MapperPlugin): this {
    this.plugins.add(plugin);
    return this;
  }

  /**
   * 🗺️ 执行对象映射
   * @param source - 源数据对象
   * @param rules - 映射规则数组
   * @param initial - 初始目标对象（可选）
   * @returns 映射后的目标对象
   * @example - 复杂映射
   * mapper.map(order, [
   *   'customerName:user.name',
   *   {
   *     target: 'totalPrice',
   *     source: 'price',
   *     transform: Transformers.number.currency('$')
   *   }
   * ]);
   */
  map<S, T extends Record<string, any>>(source: S, rules: (MappingRule | string)[], initial?: T): T & Record<string, any> {
    const target = initial || ({} as T);
    const normalizedRules = this.normalizeRules(rules);

    this.runPluginHooks('beforeMap', { source, target, rules });

    for (const rule of normalizedRules) {
      const context = this.createContext(source, target, rule);
      try {
        const rawValue = this.getSourceValue(context);
        context.value = rawValue;
        const processedValue = this.processValue(context.value, context);
        context.value = processedValue;
        if (this.shouldSkipMapping(context)) continue;

        this.setTargetValue(target, rule.targetPath, context.value);

        this.runPluginHooks('afterRule', context);
      } catch (error) {
        if (error instanceof Error) {
          this.handleError(error, context);
        } else {
          this.handleError(new Error(String(error)), context);
        }
      }
    }

    this.runPluginHooks('afterMap', { source, target, rules });
    return target as T;
  }

  /**
   * 🔄 标准化映射规则（内部处理）
   * - 将字符串简写语法转换为标准规则对象
   * - 统一处理路径解析（支持缓存优化）
   * - 合并全局配置与规则局部配置
   * @param rules - 原始规则数组（支持混合格式）
   * @returns 标准化后的规则数组（内部使用格式）
   * @example 输入 ['a:b.c', { target: 'x' }]
   *          输出 [{ targetPath: ['a'], sourcePath: ['b','c'] }, ...]
   */
  private normalizeRules(rules: (MappingRule | string)[]): NormalizedRule[] {
    const processedPaths = new Map<string, string[]>(); // 临时缓存处理过的路径

    return rules.map((rule) => {
      const baseRule = typeof rule === 'string' ? this.parseStringRule(rule) : rule;

      // 处理target路径
      let targetPath: string[];
      const targetCacheKey = Array.isArray(baseRule.target) ? baseRule.target.join('.') : baseRule.target;
      if (this.config.cachePaths && processedPaths.has(targetCacheKey)) {
        targetPath = processedPaths.get(targetCacheKey)!;
      } else {
        targetPath = this.normalizePath(baseRule.target);
        if (this.config.cachePaths) processedPaths.set(targetCacheKey, targetPath);
      }

      // 处理source路径（如果存在）
      let sourcePath: string[];
      if (baseRule.source) {
        const sourceCacheKey = Array.isArray(baseRule.source) ? baseRule.source.join('.') : baseRule.source;
        if (this.config.cachePaths && processedPaths.has(sourceCacheKey)) {
          sourcePath = processedPaths.get(sourceCacheKey)!;
        } else {
          sourcePath = this.normalizePath(baseRule.source);
          if (this.config.cachePaths) processedPaths.set(sourceCacheKey, sourcePath);
        }
      } else {
        sourcePath = targetPath; // 复用targetPath
      }

      return {
        ...baseRule,
        targetPath,
        sourcePath,
        config: { ...this.config, ...baseRule.config }
      };
    });
  }

  /**
   * 📖 解析字符串简写规则
   * - 将"target:source"格式字符串转换为规则对象
   * - 自动处理前后空格和空值情况
   * @param rule - 简写规则字符串
   * @returns 标准化映射规则对象
   * @example 'userName:user.name' => { target: 'userName', source: 'user.name' }
   */
  private parseStringRule(rule: string): MappingRule {
    const [target, source] = rule.split(':');
    return { target: target.trim(), source: source?.trim() };
  }

  /**
   * 📏 标准化路径（转为数组格式）
   * @example
   * normalizePath('a.b.c') => ['a', 'b', 'c']
   * normalizePath(['x', 'y.z']) => ['x', 'y', 'z']
   */
  public normalizePath(path: Path): string[] {
    // 如果是数组直接返回（不再分割元素）
    if (Array.isArray(path)) return path;

    const cacheKey = Array.isArray(path) ? path.join('.') : path;

    if (this.config.cachePaths && this.pathCache.has(cacheKey)) {
      return [...this.pathCache.get(cacheKey)!]; // 返回缓存副本
    }

    const segments = (Array.isArray(path) ? path : path.split('.')).flatMap((segment) => segment.split('.')).filter(Boolean);

    if (this.config.cachePaths) {
      this.pathCache.set(cacheKey, segments);
    }

    return segments;
  }

  /**
   * 🏗️ 创建映射上下文对象
   * - 合并全局配置和规则局部配置
   * - 初始化上下文核心字段
   * @param source - 当前源数据对象
   * @param target - 当前目标数据对象
   * @param rule - 当前处理的标准规则
   * @returns 完整的映射上下文对象
   * @note 上下文贯穿整个映射生命周期
   */
  private createContext(source: any, target: any, rule: NormalizedRule): MappingContext {
    // 合并全局配置和规则配置
    const mergedConfig: MappingConfig = {
      ...this.config,
      ...rule.config
    };
    return {
      source,
      target,
      rule,
      config: Object.freeze(mergedConfig),
      sourcePath: rule.sourcePath,
      targetPath: rule.targetPath,
      value: undefined // 初始化值
    };
  }

  /**
   * 🚦 判断是否跳过当前规则映射
   * - 执行插件beforeRule钩子（可阻断）
   * - 检查when条件断言结果
   * @param context - 当前映射上下文
   * @returns true表示应跳过该规则映射
   */
  private shouldSkipMapping(context: MappingContext): boolean {
    const { rule } = context;

    // 执行插件前置钩子
    if (this.runPluginHooks('beforeRule', context) === false) {
      return true;
    }

    // 检查映射条件
    if (rule.when && !rule.when(context)) {
      return true;
    }

    return false;
  }

  /**
   * 🕵️ 获取源对象值
   * - 根据sourcePath逐级访问属性
   * - 严格模式验证路径存在性
   * @param context - 当前映射上下文
   * @returns 获取到的源值或undefined
   * @throws 严格模式下路径不存在时抛出错误
   */
  private getSourceValue(context: MappingContext): any {
    const { sourcePath, config } = context.rule;

    try {
      return sourcePath.reduce((obj: Record<string, any>, key) => {
        if (config.strict && !(key in obj)) {
          throw new Error(`Missing source path: ${sourcePath.join('.')}`);
        }
        return obj?.[key];
      }, context.source);
    } catch (error) {
      if (config.strict) throw error;
      return undefined;
    }
  }

  /**
   * 🛠️ 处理空值和自动类型转换
   * @example - 自动转换日期
   * 源值"2023-01-01" → 自动转为Date对象
   */
  private processValue(rawValue: any, context: MappingContext): any {
    let value = rawValue;

    // 处理未定义值（保留原始值用于后续转换）
    if (value === undefined) {
      value = context.rule.default; // 仅设置默认值，不中断流程
    }

    // 自动类型转换
    if (context.config.autoType) {
      value = this.autoTypeConversion(value, context);
    }

    // 应用转换管道（即使 value 是 undefined 也执行）
    if (context.rule.transform) {
      const transformers = Array.isArray(context.rule.transform) ? context.rule.transform : [context.rule.transform];
      value = transformers.reduce((val, transformer) => transformer(val, context), value);
    }

    // 处理空值策略
    if (value === null) {
      switch (context.rule.config.nullPolicy) {
        case 'ignore':
          return undefined;
        case 'set-null':
          return null;
        case 'set-default':
          return context.rule.default;
      }
    }

    return value;
  }

  /**
   * 🔄 自动类型转换逻辑
   * @example - 智能转换：
   * "true" → boolean
   * "2023-01-01" → Date
   */
  private autoTypeConversion(value: any, context: MappingContext): any {
    // 实现智能类型推断逻辑
    const targetType = this.inferTargetType(context);

    if (typeof value === targetType) return value;

    try {
      switch (targetType) {
        case 'number':
          return Number(value);
        case 'boolean':
          return Boolean(value);
        case 'string':
          return String(value);
        case 'Date':
          return new Date(value);
        default:
          return value;
      }
    } catch {
      if (context.config.strict) {
        throw new Error(`Auto type conversion failed for ${value} to ${targetType}`);
      }
      return value;
    }
  }

  /**
   * 📌 设置目标对象值
   * - 自动创建嵌套对象结构
   * - 跳过undefined值设置
   * @param target - 目标对象
   * @param path - 目标路径数组
   * @param value - 要设置的值
   * @example path=['a','b','c'], value=1 => target.a.b.c = 1
   */
  private setTargetValue(target: Record<string, any>, path: string[], value: any): void {
    if (typeof value === 'undefined') return;
    path.reduce((obj: Record<string, any>, key, index) => {
      if (index === path.length - 1) {
        obj[key] = value;
        return obj;
      }
      if (!obj[key] || typeof obj[key] !== 'object') {
        obj[key] = {};
      }
      return obj[key];
    }, target);
  }

  /**
   * 🔌 执行插件钩子管道
   * - 遍历所有注册插件并按注册顺序执行指定钩子
   * - 支持通过返回false阻断后续插件执行
   * - 自动传递上下文对象给钩子函数
   * @param hookName - 要触发的钩子名称
   * @param args - 钩子函数的参数（根据类型自动推导）
   * @returns boolean | void
   *   - 返回false表示有插件要求中断后续处理
   *   - 其他情况返回undefined
   * @example
   * runPluginHooks('beforeMap', { source, target, rules })
   *
   * @note 重要行为特征：
   * 1. 插件执行顺序按照注册先后顺序
   * 2. 任意插件返回false会立即终止钩子传播
   * 3. 错误处理钩子(onError)具有特殊传播逻辑
   */
  private runPluginHooks<T extends keyof PluginHooks>(hookName: T, ...args: Parameters<PluginHooks[T]>): boolean | void {
    for (const plugin of this.plugins) {
      if (plugin[hookName]) {
        const result = (plugin[hookName] as any)(...args);
        if (result === false) return false;
      }
    }
  }

  /**
   * 🛡️ 错误处理（触发插件onError钩子）
   */
  private handleError(error: Error, context: MappingContext): void {
    const enhancedError = new Error(`Mapping failed at [${context.rule.targetPath.join('.')}]: ${error.message}`);

    if (this.runPluginHooks('onError', enhancedError, context) !== false) {
      throw enhancedError;
    }
  }

  // 基础类型推断
  private inferTargetType(context: MappingContext): 'boolean' | 'number' | 'string' | 'Date' | undefined {
    if (!context.config.autoType) return undefined;
    if (typeof context.value === 'string') {
      if (['true', 'false'].includes(context.value)) return 'boolean';
      if (/^-?\d+$/.test(context.value)) return 'number';
      if (this.isValidISODate(context.value)) return 'Date';
      return 'string';
    }
    return undefined;
  }

  /**
   * 📅 ISO日期格式验证
   * - 严格验证日期有效性（包括闰年等特殊情况）
   * - 支持完整ISO 8601格式（含时间部分）
   * @param dateString - 待验证的日期字符串
   * @returns 是否为有效ISO日期
   * @example '2023-02-29' => false（无效日期）
   *          '2023-01-01T12:00:00Z' => true
   */
  private isValidISODate(dateString: string) {
    // 正则验证 ISO 8601 格式（日期部分必须为 YYYY-MM-DD，时间部分可选）
    const isoDateRegex = /^(\d{4})-(0[1-9]|1[0-2])-(0[1-9]|[12][0-9]|3[01])(T([01][0-9]|2[0-3]):[0-5][0-9]:[0-5][0-9](\.\d+)?(Z|[+-]\d{2}:\d{2})?)?$/i;
    if (!isoDateRegex.test(dateString)) return false;

    // 提取日期部分并验证是否为有效日历日期
    const datePart = dateString.split('T')[0];
    const [year, month, day] = datePart.split('-').map(Number);
    const tempDate = new Date(year, month - 1, day); // 月份从 0 开始
    const isDateValid = tempDate.getFullYear() === year && tempDate.getMonth() === month - 1 && tempDate.getDate() === day;
    if (!isDateValid) return false;

    // 解析完整字符串并验证有效性
    const date = new Date(dateString);
    if (isNaN(date.getTime())) return false;

    // 检查 UTC 年份范围
    const utcYear = date.getUTCFullYear();
    return utcYear >= 1900 && utcYear <= 2100;
  }
}

// ======================== 🧰 扩展工具 ========================

/**
 * 🔧 内置转换器工具集
 * 涵盖字符串处理、数字格式化、日期操作、数据结构处理、数据验证等场景
 * @example - 字符串处理：
 * Transformers.string.trim()
 * @example - 日期格式化：
 * Transformers.date.format('full')(new Date())
 */
export const Transformers = {
  string: {
    /**
     * ✂️ 去除字符串两端空白字符
     * @param val - 待处理的字符串
     * @returns 修剪后的字符串
     * @example
     * trim('  hello  ') → 'hello'
     */
    trim: (val: string) => val.trim(),
    /**
     * 🔠 将字符串转为全大写格式
     * @param val - 原始字符串
     * @returns 大写格式字符串
     * @example
     * upperCase('hello') → 'HELLO'
     */
    upperCase: (val: string) => val.toUpperCase(),
    /**
     * 🔡 将字符串转为全小写格式
     * @param val - 原始字符串
     * @returns 小写格式字符串
     * @example
     * lowerCase('HELLO') → 'hello'
     */
    lowerCase: (val: string) => val.toLowerCase(),
    /**
     * 🔤 去除首尾空格并压缩中间连续空格
     * @example
     * "  hello   world  " → "hello world"
     */
    compact: (val: string) => val.trim().replace(/\s+/g, ' '),
    /**
     * 🔄 驼峰式与蛇形命名互转
     * @param from - 原始格式 ('camel' | 'snake')
     * @param to - 目标格式 ('camel' | 'snake')
     * @example
     * convertCase('camel', 'snake')('userName') → 'user_name'
     */
    convertCase: (from: 'camel' | 'snake', to: 'camel' | 'snake') => (val: string) => {
      if (from === 'camel' && to === 'snake') {
        return val.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
      }
      if (from === 'snake' && to === 'camel') {
        return val.replace(/_([a-z])/g, (_, p1) => p1.toUpperCase());
      }
      return val;
    },
    business: {
      /**
       * 📱 手机号隐私安全显示（智能国家适配版）
       * - 自动清除非数字字符
       * - 根据国家代码智能分段
       * - 支持自定义掩码字符和可见位数
       * @param countryCode 国家代码（支持CN/US/BR等）
       * @param options 配置选项
       * @param options.maskChar 掩码字符（默认*）
       * @param options.visiblePrefix 头部可见位数（默认根据国家码自动计算）
       * @param options.visibleSuffix 尾部可见位数（默认根据国家码自动计算）
       * @example
       * maskedPhone('CN')('13812345678') → '138******78'
       * maskedPhone('US', { maskChar: '#' })('1234567890') → '123###7890'
       */
      maskedPhone: (
        countryCode: string = 'CN',
        options: {
          maskChar?: string;
          visiblePrefix?: number;
          visibleSuffix?: number;
        } = {}
      ) => {
        // 国家代码预设配置
        const countryPresets: Record<string, { prefix: number; suffix: number; total: number }> = {
          CN: { prefix: 3, suffix: 4, total: 11 }, // 中国手机号
          US: { prefix: 3, suffix: 4, total: 10 }, // 美国/加拿大
          BR: { prefix: 2, suffix: 4, total: 11 }, // 巴西
          IN: { prefix: 4, suffix: 2, total: 10 } // 印度
        };

        // 获取配置或默认值
        const config = countryPresets[countryCode.toUpperCase()] || { prefix: 3, suffix: 2, total: 10 };
        const { maskChar = '*', visiblePrefix, visibleSuffix } = options;
        const prefix = visiblePrefix ?? config.prefix;
        const suffix = visibleSuffix ?? config.suffix;

        return (val: string) => {
          // 清洗输入数据
          const cleaned = val.replace(/\D/g, '');

          // 有效性验证
          if (cleaned.length !== config.total) {
            throw new Error(`Invalid phone length for ${countryCode} (expected ${config.total} digits)`);
          }

          // 计算掩码位数
          const maskLength = cleaned.length - prefix - suffix;
          if (maskLength <= 0) return cleaned; // 长度不足时返回原始值

          // 构建掩码字符串
          return `${cleaned.slice(0, prefix)}${maskChar.repeat(maskLength)}${cleaned.slice(-suffix)}`;
        };
      },

      /**
       * 🌟 通用隐私数据掩码显示
       * - 支持手机号/身份证/银行卡等多种场景
       * - 智能保留首尾位数
       * @param visiblePrefix 头部保留位数
       * @param visibleSuffix 尾部保留位数
       * @param maskChar 掩码字符（默认*）
       * @example
       * starMask(3, 4)('6225888812345678') → '622************678'
       */
      starMask: (visiblePrefix: number = 3, visibleSuffix: number = 2, maskChar: string = '*') => {
        return (val: string) => {
          const str = String(val);
          if (str.length <= visiblePrefix + visibleSuffix) return str;

          const prefix = str.slice(0, visiblePrefix);
          const suffix = str.slice(-visibleSuffix);
          const mask = maskChar.repeat(str.length - visiblePrefix - visibleSuffix);

          return `${prefix}${mask}${suffix}`;
        };
      }
    }
  },
  number: {
    /**
     * 🔢 数值精度处理（四舍五入）
     * @param precision - 保留小数位数（默认0）
     * @returns 处理后的数值
     * @example
     * round(2)(123.4567) → 123.46
     * round()('123.5') → 124
     */
    round:
      (precision = 0) =>
      (val: number | string) =>
        +Number(val).toFixed(precision),
    /**
     * 💹 货币格式化显示
     * @param symbol - 货币符号（默认$）
     * @returns 带货币符号的格式化字符串
     * @example
     * currency('¥')(99.9) → '¥99.90'
     */
    currency:
      (symbol = '$') =>
      (val: number) =>
        `${symbol}${val.toFixed(2)}`,
    /**
     * 🧮 安全转换为数字（包含非数字处理）
     * @param fallback - 转换失败时的默认值
     * @example
     * safeParse(0)('123abc') → 0
     */
    safeParse:
      (fallback: number = NaN) =>
      (val: any) => {
        const num = Number(val);
        return Number.isFinite(num) ? num : fallback;
      },
    /**
     * 📏 范围限制（最小值/最大值）
     * @param min - 允许的最小值
     * @param max - 允许的最大值
     * @example
     * clamp(0, 100)(150) → 100
     */
    clamp: (min: number, max: number) => (val: number) => Math.min(Math.max(val, min), max),

    /**
     * 〽️ 百分比格式化
     * @param precision - 小数精度
     * @param showSymbol - 是否显示%符号
     * @example
     * percentage(2, true)(0.4567) → '45.67%'
     */
    percentage:
      (precision: number = 0, showSymbol: boolean = true) =>
      (val: number) =>
        `${(val * 100).toFixed(precision)}${showSymbol ? '%' : ''}`
  },
  date: {
    /**
     * 📆 转换为ISO 8601格式字符串
     * @param val - Date对象
     * @returns ISO格式日期字符串
     * @example
     * toISO(new Date()) → '2023-10-05T12:34:56.789Z'
     */
    toISO: (val: Date) => val.toISOString(),
    /**
     * ⏱️ 转换为时间戳数值
     * @param val - Date对象或日期字符串
     * @returns 毫秒时间戳
     * @example
     * toNumber(new Date(2023, 0, 1)) → 1672531200000
     */
    toNumber: (val: Date | string) => +new Date(val),
    /**
     * 🗓️ 国际化日期格式化
     * @param format - 预设格式样式
     * @returns 格式化后的日期字符串
     * @example
     * format('full')(new Date()) → 'Tuesday, October 5, 2023'
     */
    format: (format?: 'full' | 'long' | 'medium' | 'short' | undefined) => (val: Date) => new Intl.DateTimeFormat('en-US', { dateStyle: format }).format(val),
    /**
     * 🕒 转换为时间戳（支持秒级/毫秒级）
     * @param unit - 时间单位 's'=秒, 'ms'=毫秒
     * @example
     * toTimestamp('s')(new Date()) → 1710000000
     */
    toTimestamp:
      (unit: 's' | 'ms' = 'ms') =>
      (val: Date) =>
        unit === 's' ? Math.floor(val.getTime() / 1000) : val.getTime(),
    /**
     * 🌐 本地化时间格式化（基于Intl.DateTimeFormat）
     * @param locale - 地区代码
     * @param options - 格式化选项
     * @example
     * localeFormat('zh-CN', { dateStyle: 'full' })(new Date())
     */
    localeFormat:
      (locale: string = 'en-US', options: Intl.DateTimeFormatOptions = {}) =>
      (val: Date) =>
        new Intl.DateTimeFormat(locale, options).format(val)
  },
  collection: {
    /**
     * 🧺 数组去重（支持基本类型和对象）
     * @param key - 对象元素的唯一键（处理对象数组时必填）
     * @example
     * unique()([1,2,2,3]) → [1,2,3]
     * unique('id')([{id:1}, {id:1}]) → [{id:1}]
     */
    unique:
      <T>(key?: keyof T) =>
      (arr: T[]) => {
        const seen = new Set();
        return arr.filter((item) => {
          const identifier = key ? item[key] : item;
          return seen.has(identifier) ? false : seen.add(identifier);
        });
      },

    /**
     * 🗂️ 数组分组（支持多级分组）
     * @param keys - 分组依据的键或键数组
     * @example
     * groupBy('type')(items) → { [type]: Item[] }
     */
    groupBy:
      <T>(keys: string | string[]) =>
      (arr: T[]) => {
        const keyList = Array.isArray(keys) ? keys : [keys];
        return arr.reduce((acc, item) => {
          const groupKey = keyList.map((k) => (item as any)[k]).join('|');
          acc[groupKey] = acc[groupKey] || [];
          acc[groupKey].push(item);
          return acc;
        }, {} as Record<string, T[]>);
      }
  },

  // ================= 数据验证处理 =================
  validation: {
    /**
     * 📧 邮箱格式验证与标准化
     * @param strict - 严格模式（检查TLD等高级验证）
     * @example
     * email()(' user@EXAMPLE.com ') → 'user@example.com'
     */
    email:
      (strict: boolean = false) =>
      (val: string) => {
        const normalized = val.trim().toLowerCase();
        const pattern = strict ? /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}$/ : /^\S+@\S+\.\S+$/;
        if (!pattern.test(normalized)) throw new Error('Invalid email format');
        return normalized;
      },

    /**
     * 🔗 URL标准化处理
     * - 自动添加协议头
     * - 统一路径格式
     * @example
     * url()('example.com/path') → 'http://example.com/path'
     */
    url:
      (defaultProtocol: string = 'https://') =>
      (val: string) => {
        try {
          const cleaned = val.trim().replace(/^(?!(?:\w+:)?\/\/)/, defaultProtocol);
          return cleaned;
        } catch {
          throw new Error('Invalid URL format');
        }
      }
  },

  // ================= 高级类型转换 =================
  typeConversion: {
    /**
     * 🅱️ 严格布尔值转换
     * - 真值：'true', '1', 1, true
     * - 假值：'false', '0', 0, false
     * @throws 遇到无法解析的值时抛出错误
     */
    strictBoolean: (val: any) => {
      if (typeof val === 'boolean') return val;
      if (val === 1 || val === '1' || val === 'true') return true;
      if (val === 0 || val === '0' || val === 'false') return false;
      throw new Error('Cannot convert to boolean');
    },

    /**
     * 🗄️ 深度对象克隆（结构化克隆的polyfill）
     * @note 适用于包含基础类型/数组/简单对象的场景
     */
    deepClone: <T>(val: T): T => {
      if (val === null || typeof val !== 'object') return val;
      if (Array.isArray(val)) return val.map((item) => Transformers.typeConversion.deepClone(item)) as any;
      const clone = {} as T;
      for (const key in val) {
        if (Object.prototype.hasOwnProperty.call(val, key)) {
          clone[key] = Transformers.typeConversion.deepClone(val[key]);
        }
      }
      return clone;
    }
  },

  // ================= 业务场景处理 =================
  business: {
    /**
     * 💰 多货币格式化（根据金额自动匹配符号）
     * @param locale - 地区代码
     * @example
     * autoCurrency('en-US')(100) → '$100.00'
     * autoCurrency('zh-CN')(100) → '¥100.00'
     */
    autoCurrency:
      (locale: string = 'en-US') =>
      (val: number) => {
        return new Intl.NumberFormat(locale, {
          style: 'currency',
          currency: 'USD' // 可根据locale映射真实货币
        }).format(val);
      },

    /**
     * 📱 手机号格式化（国际通用格式）
     * @param countryCode - 国家代码
     * @example
     * phoneFormat('CN')('13812345678') → '+86 138 1234 5678'
     */
    phoneFormat:
      (countryCode: string = 'CN') =>
      (val: string) => {
        const cleaned = val.replace(/\D/g, '');
        // 根据国家代码应用不同格式规则
        switch (countryCode) {
          case 'CN':
            return `+86 ${cleaned.slice(0, 3)} ${cleaned.slice(3, 7)} ${cleaned.slice(7)}`;
          case 'US':
            return `+1 (${cleaned.slice(0, 3)}) ${cleaned.slice(3, 6)}-${cleaned.slice(6)}`;
          default:
            return `+${cleaned}`;
        }
      }
  }
};

/**
 * 🎚️ 内置条件判断工具
 * @example - 类型检查：
 * Conditions.isType('string')
 * @example - 存在性检查：
 * Conditions.isTruthy
 */
export const Conditions = {
  isTruthy: (ctx: MappingContext) => !!ctx.value,
  isType: (type: string) => (ctx: MappingContext) => typeof ctx.value === type
};
